package com.asimplefox.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.asimplefox.configs.FileConfig;
import com.asimplefox.entity.Types;
import com.asimplefox.entity.VidList;
import com.asimplefox.entity.vo.VidListVo;
import com.asimplefox.mapper.VidListMapper;
import com.asimplefox.service.ITypesService;
import com.asimplefox.service.IVidListService;
import com.asimplefox.service.abst.ServiceImplAll;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.kloping.judge.Judge;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 1.添加视频名称，视频封面，视频简介，添加视频分类状态，添加视频时长 服务实现类
 * </p>
 *
 * @author kloping
 * @since 2024-10-07
 */
@Service
public class VidListServiceImpl extends ServiceImplAll<VidListMapper, VidList> implements IVidListService {

    @Autowired
    FileConfig fileConfig;

    private boolean testDuplicateEntry(VidListVo vo) {
        return lambdaQuery().eq(VidList::getName, vo.getName()).one() != null;
    }

    @Override
    public Object save(VidListVo vo, List<String> types) {
        VidList vidList = null;
        try {
            if (testDuplicateEntry(vo)) return result(-1, "视频名称重复!");
            byte[] bytes = vo.getIcon().getBytes();
            FileConfig.FileWithPath fwp = fileConfig.getFileWithPath("videos/", vo.getName() + "/icon.jpg");
            fwp.write(bytes);
            vidList = new VidList().setDesc(vo.getDesc()).setIcon(fwp.getUrl()).setName(vo.getName()).setType(vo.getType())
                    .setFtype(vo.getFtype());
            if (save(vidList)) return result(0, "上传成功!", "id", vidList.getId());
            else return result(-1, "上传失败!");
        } catch (IOException e) {
            e.printStackTrace();
            return result(-1, "封面上传失败!");
        } finally {
            if (types != null && !types.isEmpty()) {
                VidList finalVidList = vidList;
                types.forEach(e -> {
                    if (Judge.isNotEmpty(e)) {
                        typesService.save(new Types().setVlid(finalVidList.getId()).setName(e));
                    }
                });
            }
        }
    }

    @Autowired
    ITypesService typesService;

    @Value("${file.dir}")
    private String fileDir;

    @Override
    public Object update(VidListVo vo, List<String> types) {
        Integer id = vo.getId();
        if (id == null) return result(-1, "更新id不能为空!");
        VidList vidList = lambdaQuery().eq(VidList::getId, id).one();
        if (vidList == null) return result(-1, "更新id不存在!");
        try {
            if (testDuplicateEntry(vo)) return result(-1, "视频名称重复!");
            if (vo.getIcon() != null) {
                File file = new File(fileDir, vidList.getIcon());
                file.delete();

                byte[] bytes = vo.getIcon().getBytes();
                FileConfig.FileWithPath fwp = fileConfig.getFileWithPath("videos/", vo.getName() + "/icon.jpg");
                fwp.write(bytes);

                vidList.setIcon(fwp.getUrl());
            }
            vidList.setDesc(vo.getDesc()).setName(vo.getName()).setType(vo.getType()).setFtype(vo.getFtype());
            if (updateById(vidList)) return result(0, "更新成功!", "id", vidList.getId());
            else return result(-1, "更新失败!");
        } catch (IOException e) {
            e.printStackTrace();
            return result(-1, "封面上传失败!");
        } finally {
            typesService.lambdaUpdate().eq(Types::getVlid, id).remove();
            if (types != null && !types.isEmpty()) {
                VidList finalVidList = vidList;
                types.forEach(e -> {
                    if (Judge.isNotEmpty(e)) {
                        typesService.save(new Types().setVlid(finalVidList.getId()).setName(e));
                    }
                });
            }
        }
    }

    @Autowired
    VidListMapper vidListMapper;

    @Override
    public Object filterList(Integer id, String type, Integer ftype, String stype, Integer pageSize, Integer pageNum) {
        if (Judge.isNotEmpty(stype)) {
            Page<Types> pages = typesService.page(new Page<>(pageNum, pageSize), new QueryWrapper<Types>().eq("name", stype));
            JSONObject jo = JSON.parseObject(JSON.toJSONString(pages));
            jo.put("types", stype);
            jo.remove("records");
            JSONArray array = new JSONArray();
            for (Types record : pages.getRecords()) {
                VidList vidList = lambdaQuery().eq(VidList::getId, record.getVlid()).one();
                if (vidList == null) continue;
                JSONObject r = (JSONObject) JSON.toJSON(vidList);
                List<String> types = typesService.lambdaQuery().eq(Types::getVlid, record.getVlid()).list()
                        .stream().map(Types::getName).collect(Collectors.toList());
                r.put("types", types);
                array.add(r);
            }
            jo.put("records", array);
            return jo;
        }
        QueryWrapper<VidList> qw = new QueryWrapper<>();
        if (id != null && id > 0) qw.eq("id", id);
        if (Judge.isNotEmpty(type)) qw.eq("type", type);
        if (ftype != null && ftype >= 0) qw.eq("ftype", ftype);
        Page<VidList> pages = page(new Page<>(pageNum, pageSize), qw);
        JSONObject jo = JSON.parseObject(JSON.toJSONString(pages));
        jo.remove("records");
        JSONArray arr = new JSONArray();
        for (VidList record : pages.getRecords()) {
            List<Types> types = typesService.lambdaQuery().eq(Types::getVlid, record.getId()).list();
            List<String> names = types.stream().map(Types::getName).collect(Collectors.toList());
            JSONObject jr = (JSONObject) JSON.toJSON(record);
            jr.put("types", names);
            arr.add(jr);
        }
        jo.put("records", arr);
        return jo;
    }

    @Override
    public Object search(String keyword) {
        JSONArray array = new JSONArray();
        List<VidList> vidLists = lambdaQuery().like(VidList::getName, keyword).or().like(VidList::getDesc, keyword).list();
        for (VidList vidList : vidLists) {
            JSONObject jo = (JSONObject) JSON.toJSON(vidList);
            List<String> types = typesService.lambdaQuery()
                    .eq(Types::getVlid, vidList.getId()).list().stream().map(Types::getName).collect(Collectors.toList());
            jo.put("types",types);
            array.add(jo);
        }
        return array;
    }

    @Override
    public List<VidList> random(Integer count) {
        count = count < 1 ? 1 : count > 20 ? 20 : count;
        return lambdaQuery().eq(VidList::getFtype, 0).last("ORDER BY RAND() LIMIT " + count + ";").list();
    }

    @Autowired
    StringRedisTemplate week2id;

    public static final Long WEEK_TIME = 1000L * 60 * 60 * 24 * 7;

    private static final String WEEK_ONE_TIME = "weekone-time";
    private static final String WEEK_ONE = "weekone-id";

    @Override
    public Object weekone() {
        Integer id = null;
        VidList vidList = null;
        String wt = week2id.opsForValue().get(WEEK_ONE_TIME);
        String wi = week2id.opsForValue().get(WEEK_ONE);
        if (wt == null) {
            List<VidList> lists = random(1);
            vidList = lists.get(0);
            setWeekTo(vidList);
        } else {
            Long wtl = Long.valueOf(wt);
            id = Integer.valueOf(wi);
            if (wtl < System.currentTimeMillis()) {
                while (true) {
                    List<VidList> lists = random(1);
                    vidList = lists.get(0);
                    if (vidList.getId().equals(id)) continue;
                    else break;
                }
                setWeekTo(vidList);
            }
        }
        if (vidList == null) vidList = lambdaQuery().eq(VidList::getId, id).one();
        return vidList;
    }

    private void setWeekTo(VidList vidList) {
        week2id.opsForValue().set(WEEK_ONE, vidList.getId().toString());
        week2id.opsForValue().set(WEEK_ONE_TIME, String.valueOf(System.currentTimeMillis() + WEEK_TIME));
    }
}
